﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using log4net;
using SharpConfig;
using System.Threading;
using System.Net;
using System.Diagnostics;
using System.Reflection;
using System.Net.Http;

namespace SearchFileIformation
{
    public partial class ShowForm : Form
    {
        public delegate void ShowContentArgs(SearchFileEventArgs e);
        public delegate void ShowExceptionArgs(object sender, SearchFileEventArgs e);
        public delegate void WaitConcurrency(object sender, EventArgs e);
        public delegate void ConcureeencyTest(EventArgs e);
        public event ShowExceptionArgs ahowExceptionArgs;
        ShowContentArgs myShowContent;
        ShowContentArgs myMoreInformation;
        ShowExceptionArgs myShowException;
        ShowExceptionArgs myUpdateProgress;
        ShowContentArgs myProgree;
        WaitConcurrency myWaitConcurrency;
        ConcureeencyTest myConcurrency;
        SearchFile mySearchFile = new SearchFile();
        ApiObject myApiObject = new ApiObject();
        log4net.ILog log = log4net.LogManager.GetLogger("Logger");
        Dictionary<int, bool> checkSelect = new Dictionary<int, bool>();
        public const string http = "http://";
        public const string api = "api";
        public const string maxTime = "maxDelayTime";
        public const string minTime = "minDelayTime";
        public const string averageTime = "averageDelayTime";  
        int limitConcurrency, limitTimeOut;
        int concurrencyInterval;
        bool continueConcurrency = true;
        ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
        bool initData = true;
        public ShowForm()
        {
            InitializeComponent();
            listViewSelect.View = View.Details;
            mySearchFile.searchFileEvent = new SearchFile.SearchFileEvent(run);
            mySearchFile.getResponseJsonEvent = new SearchFile.GetResponseJsonEvent(moreInformation);
            myShowException = new ShowExceptionArgs(moreInformation);
            myShowContent = new ShowContentArgs(showContent);
            myMoreInformation = new ShowContentArgs(showMoreInformation);
            myUpdateProgress = new ShowExceptionArgs(updateProgress);
            myProgree = new ShowContentArgs(updateProgressBar);
            myWaitConcurrency = new WaitConcurrency(runConcurrency);
            myConcurrency = new ConcureeencyTest(ConcurrentTest);
            progressBarConcurrency.Step = 1;
            if (initData)
            {
                Configuration config = null;
                //LogWriteLock.EnterWriteLock();
                try
                {
                    config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");  
                    Section section = config["General"];
                    textBoxShowFilePath.Text = section["FilePath"].StringValue;
                    textBoxConcurrency.Text = section["TestApi_ConcurrentNumber"].StringValue;
                    textBoxTimeOut.Text = section["TestApi_TimeOut"].StringValue;
                    textBoxHost.Text = section["TestApi_Host"].StringValue;
                    textBoxPort.Text = section["TestApi_Port"].StringValue;
                    textBoxRoot.Text = section["TestApi_Root"].StringValue;
                    textBoxInterval.Text = section["ConcurrencyInterval"].StringValue;
                    limitConcurrency = int.Parse(textBoxConcurrency.Text);
                    limitTimeOut = int.Parse(textBoxTimeOut.Text);
                }
                catch (Exception e)
                {
                    log.Error(this, e);
                    textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + e.Message + "\n");
                    Directory.CreateDirectory(Application.StartupPath + "\\ApiConfig");
                    StreamWriter sw = new StreamWriter(Application.StartupPath + "\\ApiConfig\\uiparameter.cfg");
                    sw.Close();
                }
                finally
                {
                    if (config != null)
                        config.SaveToFile(Application.StartupPath + "\\ApiConfig\\uiparameter.cfg");
                    //LogWriteLock.ExitWriteLock();
                }
                initData = false;
            }      
        }

        private void buttonChoosePath_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog open = new FolderBrowserDialog();
            open.ShowDialog();
            textBoxShowFilePath.Text = open.SelectedPath;
        }
        private void buttonSearch_Click(object sender, EventArgs e)
        {
            log.Info(this);
            addTitle(myApiObject.GetType(), "selectframe");
            searchApi(textBoxShowFilePath.Text);
        }
        private void addTitle(Type titleType, string textFirstTitle="", int width=100, HorizontalAlignment position= HorizontalAlignment.Center)
        {
            ColumnHeader columnHeaderFrame = new ColumnHeader();
            columnHeaderFrame.Text = textFirstTitle;
            columnHeaderFrame.Width = width;
            columnHeaderFrame.TextAlign = position;
            listViewSelect.Columns.Add(columnHeaderFrame);
            Type apiType = titleType;
            PropertyInfo[] apiProperty = apiType.GetProperties();
            foreach (PropertyInfo item in apiProperty)      //将类属性名放入列标题
            {
                ColumnHeader columnHeader = new ColumnHeader();
                columnHeader.Text = item.Name;
                columnHeader.Width = width;
                columnHeader.TextAlign = position;
                listViewSelect.Columns.Add(columnHeader);
            }
        }
        private void searchApi(string path = "..\\..\\")
        {
            Task.Run(() => { mySearchFile.RunSearch(path); });
        }
        public void run(object sender, SearchFileEventArgs e)
        {
            if (e.GetException() != null)
            {
                log.Error(this, e.GetException());
            }   
            else
                log.Info("");
            if (InvokeRequired)
                BeginInvoke(myShowContent, e);

        }
        int sum = 0;
        string judgeChangeController = "";
        public void showContent(SearchFileEventArgs e)
        {
            ApiObject apiObject = e.GetApiContent();
            ListViewItem listViewItem = new ListViewItem();
            string status = "";
            sum++;
            try
            {
                Type apiType = apiObject.GetType();
                PropertyInfo[] property = apiType.GetProperties();
                foreach (PropertyInfo item in property)
                {
                    listViewItem.SubItems.Add(item.GetValue(apiObject).ToString()); 

                }
                if (apiObject != null)
                    listViewSelect.Items.Add(listViewItem);
                if (judgeChangeController.CompareTo(apiObject.controller) == 0)
                    return;
                else
                    judgeChangeController = apiObject.controller;
                if (e.GetException() == null)
                {
                    status = "success";
                    textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t"
                        + e.GetCount() + "\t" + e.GetApiContent().controller + "\t" + status + "\t" + "\n");
                }      
                else
                {
                    status = "false";
                    textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" 
                        + e.GetCount() + "\t" + status + "\t" + e.GetException().Message + "\n");
                }          
            }
            catch (Exception ex)
            {
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + " " + ex.Message + "\n");
                log.Error(this, ex);
            }
        }
        private void listViewSelect_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            
            try
            {
                int i = 0;
                foreach (ListViewItem listViewItem in listViewSelect.Items)
                {
                    if (listViewItem.Checked)
                    {
                        if (!checkSelect[i])
                        {
                            checkSelect.Remove(i);
                            checkSelect.Add(i, true);
                            listViewItem.BackColor = Color.Red;
                           
                        }
                    }
                    else
                    {
                        checkSelect.Remove(i);
                        checkSelect.Add(i, false);
                        listViewItem.BackColor = Color.White;
                    }
                    i++;
                }
            }
            catch(Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + " " + ex.Message + "\n");
            }    
        } 
        private void textBoxConcurrency_TextChanged(object sender, EventArgs e)
        {
            Configuration config = null;
            LogWriteLock.EnterWriteLock();
            try
            {
                if (textBoxConcurrency.Text.Length > 5)
                {
                    textBoxSystemStatus.AppendText("并发数小于100000\n");
                    textBoxConcurrency.Text = "";
                }
                else
                {
                    if (textBoxConcurrency.Text != "")
                        limitConcurrency = int.Parse(textBoxConcurrency.Text);
                    config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");
                    config["General"]["TestApi_ConcurrentNumber"].SetValue(textBoxConcurrency.Text);                  
                }       
            }
            catch (Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + " " + ex.Message + "\n");
            }
            finally
            {
                
                config.SaveToFile("ApiConfig\\uiparameter.cfg");
                LogWriteLock.ExitWriteLock();
            }
            
        }

        private void buttonApiTest_Click(object sender, EventArgs e)
        {
            turnOffButton();
            clearDelayTime();
            getChooseApi(false);
        }

        private void checkBoxAllSelect_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxAllSelect.Checked)
            {
                foreach(ListViewItem item in listViewSelect.Items)  //设置全选
                {
                    item.Checked = true;
                    item.Selected = true;
                }
            }
            else
            {
                foreach (ListViewItem item in listViewSelect.Items)     //全不选
                {
                    item.Checked = false;
                    item.Selected = false;
                }
            }
        }

        private void buttonConcurrentTest_Click(object sender, EventArgs e)
        {
            turnOffButton();
            clearDelayTime();
            getChooseApi();
        }
        private void ConcurrentTest(EventArgs e)
        {
            turnOffButton();
            clearDelayTime();
            getChooseApi();
        }
        private void getChooseApi(bool chooseCurrent=true)
        {
            Dictionary<int, List<string>> chooseApi = new Dictionary<int, List<string>>();
            List<int> chooseApiPosition = new List<int>();
            Test test = new Test();
            int i = 0;
            foreach(ListViewItem item in listViewSelect.Items)
            {
                if (item.Checked)
                {
                    List<string> api = new List<string>();
                    for (int j = 0; j < item.SubItems.Count; j++)
                        api.Add(item.SubItems[j].Text);
                    chooseApi.Add(i, api);
                    chooseApiPosition.Add(i);
                }
                i++;
            }
            test.testHandler = new Test.TestHandler(moreInformation);
            test.updateProgree = new Test.UpdateProgree(updateProgress);
            test.testConcurrentEvent += test.testConcurrent;
            if (chooseCurrent)
            {
                test.pushMessage(chooseApi, chooseApiPosition, limitConcurrency,
                    limitTimeOut, textBoxHost.Text, textBoxPort.Text, textBoxRoot.Text, this);
                progressBarConcurrency.Maximum = limitConcurrency*chooseApiPosition.Count;
                progressBarConcurrency.Value = 0;
            }
            else
            {
                test.pushMessage(chooseApi, chooseApiPosition, 1,
                    limitTimeOut, textBoxHost.Text, textBoxPort.Text, textBoxRoot.Text, this, false);
                progressBarConcurrency.Maximum = chooseApiPosition.Count;
                progressBarConcurrency.Value = 0;
            }     
        }
        private void limitEnter(object sender, KeyPressEventArgs e)
        {
            if (!(char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
                e.Handled = true;
        }

        private void textBoxTimeOut_TextChanged(object sender, EventArgs e)
        {
            Configuration config = null;
            LogWriteLock.EnterWriteLock();
            try
            {
                if (textBoxTimeOut.Text.Length > 6)
                {
                    textBoxSystemStatus.AppendText("TimeOut小于1000000\n");
                    textBoxTimeOut.Text = "";
                }
                else
                {
                    if (textBoxTimeOut.Text != "")
                        limitTimeOut = int.Parse(textBoxTimeOut.Text);
                    config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");
                    config["General"]["TestApi_TimeOut"].SetValue(textBoxTimeOut.Text);
                }
            }
            catch (Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + ex.Message + "\n");
            }
            finally
            {
                
                config.SaveToFile("ApiConfig\\uiparameter.cfg");
                LogWriteLock.ExitWriteLock();
            }
            
        }

        private void buttonClearSystemInformation_Click(object sender, EventArgs e)
        {
            textBoxSystemStatus.Clear();
        }

        private void buttonOutApi_Click(object sender, EventArgs e)
        {
            Directory.CreateDirectory(Application.StartupPath + "\\OutApi");
            LogWriteLock.EnterWriteLock();
            StreamWriter sw = null;
            try
            {
                sw = new StreamWriter("OutApi\\TestApiDataController.csv");
                for (int i = 0; i < listViewSelect.Columns.Count; i++)
                {
                    if (i < listViewSelect.Columns.Count - 1)
                        sw.Write(listViewSelect.Columns[i].Text + "*");
                    else
                        sw.Write(listViewSelect.Columns[i].Text);
                }
                sw.Write("\n");

                foreach (ListViewItem item in listViewSelect.Items)
                {
                    for (int i = 0; i < item.SubItems.Count; i++)
                    {
                        if (i < item.SubItems.Count - 1)
                            sw.Write(item.SubItems[i].Text + "*");
                        else
                            sw.Write(item.SubItems[i].Text);
                    }
                    sw.Write("\n");
                }
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + " \t导出成功!\n");
            }
            catch(Exception ex)
            {
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + " \t导出失败!\t" + ex.Message + "\n");
                myShowException(this, new SearchFileEventArgs(ex));
            }
            finally
            {
                if (sw != null)
                    sw.Close();
                LogWriteLock.ExitWriteLock();
            }    
        }

        private void buttonPutApi_Click(object sender, EventArgs e)
        {
            try
            {
                string[] path = Directory.GetFiles(@"..\\..\\",
                "*Controller.csv", System.IO.SearchOption.AllDirectories);
                if (path != null && listViewSelect.Columns.Count==0)
                {
                    StreamReader sr = new StreamReader(path[0]);
                    string[] title = sr.ReadLine().Split('*');
                    for (int i = 0; i < title.Length; i++)
                    {
                        ColumnHeader columnHeader = new ColumnHeader();
                        columnHeader.Text = title[i];
                        columnHeader.Width = 100;
                        columnHeader.TextAlign = HorizontalAlignment.Center;
                        listViewSelect.Columns.Add(columnHeader);
                    }
                }
                foreach (string subPath in path)
                {
                    Dictionary<int, string> textcontent = new Dictionary<int, string>();
                    int fileLength = File.ReadAllLines(subPath).Length;
                    StreamReader sr = new StreamReader(subPath);
                    for (int i = 0; i < fileLength; i++)
                    {
                        textcontent.Add(i, sr.ReadLine());
                    }
                    sr.Close();
                    for (int i = 1; i < fileLength; i++)
                    {
                        string[] content = textcontent[i].Split('*');
                        ListViewItem item = new ListViewItem();
                        for (int j = 1; j < content.Length; j++)
                        {
                            item.SubItems.Add(content[j]);
                        }
                        listViewSelect.Items.Add(item);
                    }
                }
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + " \t导入成功!\n");
            }
            catch(Exception ex)
            {
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + " \t导入失败!\n");
                SearchFileEventArgs sfe = new SearchFileEventArgs(ex);
                myShowException(this,sfe);
            }   
        }

        public void moreInformation(object sender, SearchFileEventArgs e)
        {
            if (e.GetException() != null)
            {
                log.Error(this, e.GetException());
            }
            else
                log.Info("");
            if (InvokeRequired)
                BeginInvoke(myMoreInformation, e);
        }
        private void showMoreInformation(SearchFileEventArgs e)
        {
            if(e.getApiPositionInformation() != null && e.getApiPositionInformation().testStatu)
            {
                turnOnButton();
            }
                
            if (e.GetException() != null)
            {
                if (e.getApiPositionInformation() != null && e.getApiPositionInformation().color != Color.White)
                    listViewSelect.Items[e.getApiPositionInformation().position].BackColor =
                        e.getApiPositionInformation().color;
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + e.getApiPositionInformation().api
                    + "\t" + e.GetException().Message + "\n");                
            }
            else if (e.getApiPositionInformation() != null)
            {
                Dictionary<string, int> apiIndex = myApiObject.GetApiIndex();
                if(e.getApiPositionInformation().color != Color.White)
                    listViewSelect.Items[e.getApiPositionInformation().position].BackColor = 
                        e.getApiPositionInformation().color;
                if (e.getApiPositionInformation().maxDelayTime != null)
                {
                    listViewSelect.Items[e.getApiPositionInformation().position].SubItems[apiIndex[maxTime]].Text =
                        e.getApiPositionInformation().maxDelayTime;
                    listViewSelect.Items[e.getApiPositionInformation().position].SubItems[apiIndex[minTime]].Text =
                        e.getApiPositionInformation().minDelayTime;
                    listViewSelect.Items[e.getApiPositionInformation().position].SubItems[apiIndex[averageTime]].Text =
                        e.getApiPositionInformation().averageDelayTime;
                }
            }
            //访问测试使用
            if (e.GetInformation() != "" && e.GetInformation() != null && e.GetInformation().CompareTo("end") != 0)
            {
                if (progressBarConcurrency.Value < progressBarConcurrency.Maximum)
                    progressBarConcurrency.Value++;
                if (e.getApiPositionInformation() != null)
                {
                    listViewSelect.Items[e.getApiPositionInformation().position].BackColor = e.getApiPositionInformation().color;
                    if (!e.GetInformation().StartsWith("<") || e.GetInformation().StartsWith("error"))
                        textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" +
                            e.getApiPositionInformation().api + "\t" + e.GetInformation() + "\n");
                    else
                    {
                        textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" +
                            e.getApiPositionInformation().api + "\t返回HTML页面。\n");
                    }
                }  
            }
            //判断搜索结束使用
            if (e.GetInformation() !=null && e.GetInformation().CompareTo("end") == 0)      
            {
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + sum + "\tallApiSum\n");
                sum = 0;
            }               
        }
        private void turnOnButton()
        {
            textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t测试结束！\n");
            buttonApiTest.Enabled = true;
            buttonChoosePath.Enabled = true;
            buttonConcurrentTest.Enabled = true;
            buttonSearch.Enabled = true;        
            if (continueConcurrency)
            {
                Task.Run(() => waitConcurrency());
            }
        }
        private void waitConcurrency()
        {
            Thread.Sleep(concurrencyInterval);
            myWaitConcurrency(null, null);
        }
        private void runConcurrency(object sender, EventArgs e)
        {
            if (InvokeRequired)
                BeginInvoke(myConcurrency, e);
        }
        private void turnOffButton()
        {
            textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t测试开始！\n");
            buttonApiTest.Enabled = false;
            buttonChoosePath.Enabled = false;
            buttonConcurrentTest.Enabled = false;
            buttonSearch.Enabled = false;
        }

        private void textBoxHost_TextChanged(object sender, EventArgs e)
        {
            Configuration config = null;
            LogWriteLock.EnterWriteLock();
            try
            {
                config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");
                config["General"]["TestApi_Host"].SetValue(textBoxHost.Text);           
            }
            catch(Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + ex.Message + "\n");
            }
            finally
            {
                
                config.SaveToFile("ApiConfig\\uiparameter.cfg");
                LogWriteLock.ExitWriteLock();
            }
            
        }

        private void textBoxPort_TextChanged(object sender, EventArgs e)
        {
            Configuration config = null;
            LogWriteLock.EnterWriteLock();
            try
            {
                config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");
                config["General"]["TestApi_Port"].SetValue(textBoxPort.Text);          
            }
            catch(Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + ex.Message + "\n");
            }
            finally
            {
                config.SaveToFile("ApiConfig\\uiparameter.cfg");
                LogWriteLock.ExitWriteLock();
            }
            
        }

        private void textBoxRoot_TextChanged(object sender, EventArgs e)
        {
            Configuration config = null;
            LogWriteLock.EnterWriteLock();
            try
            {
                config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");
                config["General"]["TestApi_Root"].SetValue(textBoxRoot.Text);        
            }
            catch(Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + ex.Message + "\n");
            }
            finally
            {
                
                config.SaveToFile("ApiConfig\\uiparameter.cfg");
               LogWriteLock.ExitWriteLock();
            }
           
        }

        private void textBoxShowFilePath_TextChanged(object sender, EventArgs e)
        {
            Configuration config = null;
            LogWriteLock.EnterWriteLock();
            try
            {
                config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");
                config["General"]["FilePath"].SetValue(textBoxShowFilePath.Text);            
            }
            catch(Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + ex.Message + "\n");
            }
            finally
            {
                
                config.SaveToFile("ApiConfig\\uiparameter.cfg");
                LogWriteLock.ExitWriteLock();
            }
            
        }

        private void textBoxInterval_TextChanged(object sender, EventArgs e)
        {
            Configuration config = null;
            LogWriteLock.EnterWriteLock();
            try
            {
                concurrencyInterval = int.Parse(textBoxInterval.Text);
                config = Configuration.LoadFromFile("ApiConfig\\uiparameter.cfg");
                config["General"]["ConcurrencyInterval"].SetValue(textBoxInterval.Text);   
            }
            catch(Exception ex)
            {
                log.Error(this, ex);
                textBoxSystemStatus.AppendText(DateTime.Now.ToString() + "\t" + ex.Message + "\n");
            }
            finally
            {
                
                config.SaveToFile("ApiConfig\\uiparameter.cfg");
                LogWriteLock.ExitWriteLock();
            }
            
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
                continueConcurrency = true;
            else
                continueConcurrency = false;
        }

        private void clearDelayTime()
        {
            Dictionary<string, int> apiIndex = myApiObject.GetApiIndex();
            foreach (ListViewItem listViewItem in listViewSelect.Items)
            {
                listViewItem.BackColor = Color.White;
                listViewItem.SubItems[apiIndex[maxTime]].Text = "";
                listViewItem.SubItems[apiIndex[minTime]].Text = "";
                listViewItem.SubItems[apiIndex[averageTime]].Text = "";
            }
        }
        private void updateProgress(object sender, SearchFileEventArgs e)
        {
            if (InvokeRequired)
                BeginInvoke(myProgree, e);
        }
        object ob = new object();
        private void updateProgressBar(SearchFileEventArgs e)
        {
            lock (ob)
            {
                if (progressBarConcurrency.Value < progressBarConcurrency.Maximum)
                    progressBarConcurrency.Value++;
            }   
        }
    }
}